from django.contrib.auth.models import AnonymousUser

from rest_framework.authtoken.models import Token

from channels.auth import AuthMiddlewareStack
from channels.db import database_sync_to_async

import urllib.parse

@database_sync_to_async
def get_user(token):
    try:
        token = Token.objects.get(key=token)
        return token.user
    except Token.DoesNotExist:
        return AnonymousUser()

class TokenAuthMiddleware:
    def __init__(self, inner):
        self.inner = inner
    def __call__(self, scope):
        return TokenAuthMiddlewareInstance(scope, self)


class TokenAuthMiddlewareInstance:
    """
    Yeah, this is black magic:
    https://github.com/django/channels/issues/1399
    """
    def __init__(self, scope, middleware):
        self.middleware = middleware
        self.scope = dict(scope)
        self.inner = self.middleware.inner

    async def __call__(self, receive, send):
        decoded_qs = urllib.parse.parse_qs(self.scope["query_string"])
        if b'token' in decoded_qs:
          token = decoded_qs.get(b'token').pop().decode()
          self.scope['user'] = await get_user(token)
          inner = self.inner(self.scope)
          return await inner(receive, send)


TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))